/**
 * \file    builder.h
 * \brief   Build the action table from a generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    October 2, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#ifndef BUILDER_H
#define BUILDER_H

#include "state.h"
#include "coder.h"
#include "generator.h"
#include "transaction.h"
#include "common.h"

LPP_NAMESPACE_BEGIN

class Builder {
public:

    /*
    ** Each state contains a set of token transaction and a set of
    ** non terminal transactions.  Each of these sets makes an instance
    ** of the following structure.  An array of these structures is used
    ** to order the creation of entries in the yy_action[] table.
    */
    class ActionsProxy {
    public:
        ActionIndex index_m;          /* Original order of action proxy */
        ActionsProxy(const StateRef &state
                    , bool const is_terminal
                    , ActionIndex const index);
        ActionIndex number_of_actions() const;
        bool operator < (ActionsProxy const & rhs) const;
        friend void swap(ActionsProxy & a, ActionsProxy & b) {
            using std::swap; // bring in swap for built-in types
//            DEBUG_MESSAGE("BEFORE SWAP: %lu,%s,%lu<->%lu,%s,%lu"
//                          ,a.index_m,a.is_terminal_m?"y":"n",a.state_m->id()
//                          ,b.index_m,b.is_terminal_m?"y":"n",b.state_m->id());
            swap(a.index_m, b.index_m);
            swap(a.is_terminal_m, b.is_terminal_m);
            swap(a.state_m, b.state_m);
            swap(a.number_of_actions_m, b.number_of_actions_m);
//            DEBUG_MESSAGE("AFTER  SWAP: %lu,%s,%lu<->%lu,%s,%lu"
//                          ,a.index_m,a.is_terminal_m?"y":"n",a.state_m->id()
//                          ,b.index_m,b.is_terminal_m?"y":"n",b.state_m->id());
        }

        ActionRefMap const & actions() const;
        ActionOffset & offset() const;
        bool is_terminal() const;
        ActionsProxy & operator= (ActionsProxy const & AsP) {
            if (this != &AsP) {
                index_m = AsP.index_m;
                state_m = AsP.state_m;
                is_terminal_m = AsP.is_terminal_m;
                number_of_actions_m = AsP.number_of_actions_m;
            }
            return *this;
        }
        ActionsProxy(ActionsProxy const & AsP)
            : index_m(AsP.index_m)
            , state_m(AsP.state_m)
            , is_terminal_m(AsP.is_terminal())
            , number_of_actions_m(AsP.number_of_actions_m) {
            ;
        }
        ActionsProxy(ActionsProxy && AsP)
            : index_m(AsP.index_m)
            , state_m(AsP.state_m)
            , is_terminal_m(AsP.is_terminal())
            , number_of_actions_m(AsP.number_of_actions_m) {
            ;
        }
        StateRef const & state() const {
            return state_m;
        }
    private:
        StateRef state_m;// swap
        bool is_terminal_m;
        ActionIndex number_of_actions_m;
    };

public:
    Generator const & generator() const {
        return generator_m;
    }
    typedef Transactions::size_type TransactionIndex;
    TransactionIndex number_of_actions() const {
        return number_of_actions_m;
    }
    void number_of_actions(TransactionIndex const i) {
        number_of_actions_m = i;
    }
    StringSet const built_actions(bool all = true) const;
    StringSet const built_actions_1(bool all = true) const;
    StringSet const built_actions_2(bool all = true) const;
    StringSet const simple_built_actions() const;

    ActionOffset shift_use_default() const {
        return min_terminal_offset_m-1;
    }
    Builder(Generator &generator);
    Coder & coder() {
        return coder_m;
    }
    Coder const & coder() const {
        return coder_m;
    }
    Transactions action_table() const {
        return action_table_m;
    }
    ActionOffset min_terminal_offset() const {
        return min_terminal_offset_m;
    }
    ActionOffset max_terminal_offset() const {
        return max_terminal_offset_m;
    }
    ActionOffset max_non_terminal_offset() const {
        return max_non_terminal_offset_m;
    }
    ActionOffset min_reduce_offset() const;
    ActionOffset min_shift_offset() const;
    typedef std::map<SymbolIndex,SymbolIndex> CheckerMap;
private:
    Generator const & generator_m;
    Transactions action_table_m;         /* The yy_action[] table under construction */
    ActionOffset max_terminal_offset_m;
    ActionOffset min_terminal_offset_m;
    ActionOffset max_non_terminal_offset_m;
    ActionOffset min_non_terminal_offset_m;
    TransactionIndex number_of_actions_m;
    Coder coder_m;
};

LPP_NAMESPACE_END

#endif // BUILDER_H
